package com.ruoyi.common.utils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;

import com.alibaba.fastjson2.JSONObject;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 数据处理类
 * 
 * @author lincm
 * @date 2022/11/16
 */
@Slf4j
public class DataUtil {

    /**
     * 校验手机为11位
     */
    public static final String PHONE_MOBILE = "^1\\d{10}$";

    /**
     * 校验邮箱
     */
    public static final String EMAIL = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$";

    private static final String FILL_CHARS = "abcdefghjklmnpqrstuvwxyz";

    public static String encodeId(String id) {
        try {
            // 1. 将ID转为36进制
            long numericId = Long.parseLong(id);
            String base36 = Long.toString(numericId, 36);

            // 2. 生成固定校验码（基于ID）
            int checksum = id.chars().map(Character::getNumericValue).sum();
            String checksumBase36 = Integer.toString(checksum, 36);

            // 3. 将base36和校验码的长度编码进去
            String lengthInfo = Integer.toString(base36.length(), 36) + Integer.toString(checksumBase36.length(), 36);

            // 4. 组合主体部分
            String mainPart = lengthInfo + base36 + checksumBase36;

            // 5. 用小写字母填充到20位
            String padding = FILL_CHARS.repeat(4).substring(0, 20 - mainPart.length());

            return (mainPart + padding).toLowerCase();
        } catch (Exception error) {
            System.err.println("Encode error: " + error.getMessage());
            return null;
        }
    }

    public static Long getSnowflakeId() {
        Snowflake snowflake = IdUtil.getSnowflake(1, 1);
        return snowflake.nextId();
    }

    /**
     * 手机
     * 
     * @param value String 值
     * @param info String 字段名
     */
    public static Boolean isMobile(String value) {
        return regularException(value, PHONE_MOBILE, "手机");
    }

    /**
     * 邮箱
     * 
     * @param value String 值
     * @param info String 字段名
     * @author Mr.Zhang
     * @since 2020-05-11
     */
    public static Boolean isEmail(String value) {
        return regularException(value, EMAIL, "邮箱");
    }

    /**
     * 正则表达式验证
     * 
     * @param value String 值
     * @param info String 字段名
     * @param regular String 正则表达式
     * @author Mr.Zhang
     * @since 2020-05-11
     */
    public static Boolean regularException(String value, String regular, String title) {
        return regular(value, regular);
    }

    /**
     * 正则表达式验证
     * 
     * @param value String 值
     * @param info String 字段名
     * @param regular String 正则表达式
     * @author Mr.Zhang
     * @since 2020-05-11
     */
    public static boolean regular(String value, String regular) {
        Pattern pattern = Pattern.compile(regular);
        return pattern.matcher(value).matches();
    }

    //
    // /**
    // * 对象转map
    // * @param object 对象
    // * @author Mr.Zhang
    // * @since 2020-04-14
    // * @return Map
    // */
    // public static Map objectToMap(Object object){
    //
    //
    // new JSONConverter().
    //
    // return JSONObject.parseObject(JSONObject.toJSONString(object), Map.class);
    // }
    //
    // public static Map StringToMap(String strValue){
    // return JSONObject.parseObject(strValue, HashMap.class);
    // }
    //
    // /**
    // * map转对象
    // * @param map map
    // * @param clz 对象
    // * @author Mr.Zhang
    // * @since 2020-04-14
    // * @return Map
    // */
    // public static <T> T mapToObj(HashMap<String,Object> map, Class<T> clz){
    // if (map == null) {
    // return null;
    // }
    // return JSONObject.parseObject(JSONObject.toJSONString(map), clz);
    // }
    //
    // /**
    // * map转对象
    // * @param map map
    // * @param clz 对象
    // * @author Mr.Zhang
    // * @since 2020-04-14
    // * @return Map
    // */
    // public static <T> T mapStringToObj(HashMap<String,String> map, Class<T> clz){
    // if (map == null) return null;
    // return JSONObject.parseObject(JSONObject.toJSONString(map), clz);
    // }
    //
    //
    // /**
    // * 密码工具
    // * @param args String[] 字符串数组
    // */
    // public static void main(String[] args) throws Exception {
    //// log.info(encryptPassword("123456", "admin"));
    // log.info(decryptPassowrd("", ""));
    // }

    /**
     * map合并
     * 
     * @param map 对象
     * @author Mr.Zhang
     * @since 2020-04-14
     * @return Object
     */
    public static Map<String, Object> mergeMap(Map<String, Object> map, Map<String, Object> map1) {
        HashMap<String, Object> map2 = new HashMap<>(16);
        map2.putAll(map);
        map2.putAll(map1);
        return map2;
    }

    /**
     * 字符串分割，转化为数组
     * 
     * @param str 字符串
     * @author Mr.Zhang
     * @since 2020-04-22
     * @return List<Integer>
     */
    public static List<Integer> stringToArray(String str) {
        return stringToArrayByRegex(str, ",");
    }

    /**
     * 字符串分割，转化为数组
     * 
     * @param str 字符串
     * @param regex 分隔符有
     * @author Mr.Zhang
     * @since 2020-04-22
     * @return List<Integer>
     */
    public static List<Integer> stringToArrayByRegex(String str, String regex) {
        List<Integer> list = new ArrayList<>();
        if (str.contains(regex)) {

            String[] split = str.split(regex);

            for (String value : split) {
                if (!StringUtils.isBlank(value)) {
                    list.add(Integer.parseInt(value.trim()));
                }
            }
        } else {
            list.add(Integer.parseInt(str));
        }
        return list;
    }

    /**
     * 字符串分割，转化为数组
     * 
     * @param str 字符串
     * @author Mr.Zhang
     * @since 2020-04-22
     * @return List<String>
     */
    public static List<String> stringToArrayStr(String str) {
        return stringToArrayStrRegex(str, ",");
    }

    /**
     * 数字字符数据转int格式数据
     * 
     * @param str 待转换的数字字符串
     * @return int数组
     */
    public static List<Integer> stringToArrayInt(String str) {
        List<String> strings = stringToArrayStrRegex(str, ",");
        List<Integer> ids = new ArrayList<>();
        for (String string : strings) {
            ids.add(Integer.parseInt(string.trim()));
        }
        return ids;
    }

    /**
     * 字符串分割，转化为数组
     * 
     * @param str 字符串
     * @param regex 分隔符有
     * @author Mr.Zhang
     * @since 2020-04-22
     * @return List<String>
     */
    public static List<String> stringToArrayStrRegex(String str, String regex) {
        List<String> list = new ArrayList<>();
        if (str.contains(regex)) {
            String[] split = str.split(regex);
            for (String value : split) {
                if (!StringUtils.isBlank(value)) {
                    list.add(value);
                }
            }
        } else {
            list.add(str);
        }
        return list;
    }

    /**
     * 字符串分割，转化为数组
     * 
     * @param str 字符串
     * @author Mr.Zhang
     * @since 2020-04-22
     * @return List<Object>
     */
    public static List<Object> stringToArrayObject(String str) {
        return stringToArrayObjectRegex(str, ",");
    }

    /**
     * 字符串分割，转化为数组
     * 
     * @param str 字符串
     * @param regex 分隔符有
     * @author Mr.Zhang
     * @since 2020-04-22
     * @return List<Object>
     */
    public static List<Object> stringToArrayObjectRegex(String str, String regex) {
        List<Object> list = new ArrayList<>();
        if (str.contains(regex)) {

            String[] split = str.split(regex);

            for (String value : split) {
                if (!StringUtils.isBlank(value)) {
                    list.add(value);
                }
            }
        } else {
            list.add(str);
        }
        return list;
    }

    /**
     * json字符串转数组
     * 
     * @param str 字符串
     * @author Mr.Zhang
     * @since 2020-04-22
     * @return List<String>
     */
    public static List<String> jsonToListString(String str) {
        try {
            JSONArray objects = JSONUtil.parseArray(str);
            return JSONUtil.toList(objects, String.class);
        } catch (Exception e) {
            ArrayList<String> list = new ArrayList<>();
            list.add(str);
            return list;
        }
    }

    /**
     * json字符串转数组
     * 
     * @param str 字符串
     * @author Mr.Zhang
     * @since 2020-04-22
     * @return List<Integer>
     */
    public static List<Integer> jsonToListInteger(String str) {
        try {
            JSONArray objects = JSONUtil.parseArray(str);
            return JSONUtil.toList(objects, Integer.class);
        } catch (Exception e) {
            ArrayList<Integer> list = new ArrayList<>();
            list.add(Integer.parseInt(str));
            return list;
        }
    }

    /**
     * json字符串转数组
     * 
     * @param str 字符串
     * @author Mr.Zhang
     * @since 2020-04-22
     * @return List<Integer>
     */
    public static List<Object> jsonToListObject(String str) {
        try {
            JSONArray objects = JSONUtil.parseArray(str);
            return JSONUtil.toList(objects, Object.class);
        } catch (Exception e) {
            ArrayList<Object> list = new ArrayList<>();
            list.add(str);
            return list;
        }
    }

    /**
     * json字符串转数组
     * 
     * @param str 字符串
     * @author Mr.Zhang
     * @since 2020-04-22
     * @return List<T>
     */
    public static <T> List<T> jsonToListClass(String str, Class<T> cls) {
        try {
            JSONArray objects = JSONUtil.parseArray(str);
            return JSONUtil.toList(objects, cls);
        } catch (Exception e) {
            return new ArrayList<>();
        }
    }

    public static String getRandomNumber(int length) {
        // 定义一个字符串(A-Z,a-z,0-9),一共62为
        String str = "0123456789";
        // 由Random生成随机数
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        // 长度为几就循环几次
        for (int i = 0; i < length; i++) {
            // 产生0-61的数字
            int number = random.nextInt(10);
            sb.append(str.charAt(number));
        }
        return sb.toString();
    }

    public static String getRandomChat(int length) {
        // 定义一个字符串(A-Z,a-z,0-9),一共62为
        String str = "abcdefghijklmnopqrstuvwzyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        // 由Random生成随机数
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        // 长度为几就循环几次
        for (int i = 0; i < length; i++) {
            // 产生0-61的数字
            int number = random.nextInt(62);
            sb.append(str.charAt(number));
        }
        log.info("RandomChat = {}", sb.toString());
        return sb.toString();
    }

    /**
     * 根据长度生成随机数字
     * 
     * @param start 起始数字
     * @param end 结束数字
     * @return 生成的随机码
     */
    public static Integer randomCount(Integer start, Integer end) {
        return (int)(Math.random() * (end - start + 1) + start);
    }

    /**
     * 订单号生成
     * 
     * @param payType String 支付类型
     * @return 生成的随机码
     */
    public static String getOrderNo(String payType) {
        return payType + randomCount(11111, 99999) + System.currentTimeMillis() + randomCount(11111, 99999);
    }

    /**
     * 过滤非数字
     * 
     * @param str
     * @return
     */
    public static Integer getNumeric(String str) {
        String regEx = "[^0-9]";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(str);
        String num = m.replaceAll("").trim();
        return Integer.parseInt(num);
    }

    /**
     * @Title: replace
     * @Description: 字符串花括号替换
     * @param msg
     * @param params
     * @return String
     * @throws
     */
    public static String format(String msg, Object... params) {
        if (msg == null) {
            throw new NullPointerException("msg");
        }
        StringBuffer sb = new StringBuffer();
        // 定界符
        final String delimiter = "\\{}";
        final String limiter = "{}";
        // 括号出现的计数值
        int cnt = 0;
        int plength = params == null ? 0 : params.length;
        if (params != null && params.length > 0) {
            if (msg.indexOf(limiter) == -1) {
                return msg;
            } else {
                String[] msgsubs = msg.split(delimiter);
                for (String msgsub : msgsubs) {
                    sb.append(msgsub);
                    if (plength > cnt) {
                        sb.append(String.valueOf(params[cnt]));
                    }
                    cnt++;
                }
            }
            // for (int i = 0; i < params.length; i++) {
            // int tmpIndex = msg.indexOf(delimiter);
            // // 不存在赋值
            // if (tmpIndex == -1) {
            // if (cnt == 0) {
            // sb.append(msg);
            // }
            // break;
            // } else {
            // // 存在则进行赋值拼接
            // String str = msg.substring(0, tmpIndex);
            // msg = msg.substring((tmpIndex + 2), msg.length());
            // String valStr = params[i].toString();
            // sb.append(str).append(valStr);
            // cnt++;
            //
            // }
            // }
        } else {// param为空时
            sb.append(msg);
        }
        return sb.toString();
    }

    /**
     * 将Byte数组转换成文件
     * 
     * @param bytes byte数组
     * @param filePath 文件路径 如 D://test/ 最后“/”结尾
     * @param fileName 文件名
     */
    public static void BytesToFile(byte[] bytes, String filePath, String fileName) {
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        File file = null;
        try {

            file = new File(filePath + fileName);
            if (!file.getParentFile().exists()) {
                // 文件夹不存在 生成
                file.getParentFile().mkdirs();
            }
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void StringToFile(String data, String filePath, String fileName) throws IOException {
        FileOutputStream fos = new FileOutputStream(filePath + fileName);
        InputStream is = toInputStream(data);
        byte[] b = new byte[1024];
        while ((is.read(b)) != -1) {
            fos.write(b);// 写入数据
        }
        is.close();
        fos.close();// 保存数据

    }

    public static InputStream toInputStream(String imgData) {
        if (imgData == null) {
            return null;
        }
        Decoder decoder = Base64.getDecoder();
        // Base64解码
        byte[] b = decoder.decode(imgData);
        for (int i = 0; i < b.length; ++i) {
            if (b[i] < 0) {// 调整异常数据
                b[i] += 256;
            }
        }
        return new ByteArrayInputStream(b);
    }

    public static String encrypt(Integer inviteId) {
        inviteId = inviteId + 1234567890;
        // System.out.println("inviteId:" + inviteId);
        String str = inviteId.toString();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < str.length(); i = i + 2) {
            String result = Integer.toHexString(Integer.parseInt(str.substring(i, i + 2)));
            result = result.length() == 1 ? "0" + result : result;
            sb.append(result);
            // System.out.println(result + ":" + str.substring(i, i + 2));
        }
        return sb.toString();
        // HexUtil.encodeHexStr(inviteId.toString(), CharsetUtil.CHARSET_UTF_8);
    }

    public static Integer decryptStr(String inviteId) {
        // inviteId = inviteId + 1234567890;
        System.out.println("inviteId:" + inviteId);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < inviteId.length(); i = i + 2) {
            String result = String.valueOf(Integer.parseInt(inviteId.substring(i, i + 2), 16));
            result = result.length() == 1 ? "0" + result : result;
            sb.append(result);
            System.out.println(result + ":" + inviteId.substring(i, i + 2));
        }
        return Integer.parseInt(sb.toString()) - 1234567890;
    }

    public static JSONObject merge(JSONObject main, JSONObject param) {
        String tmp = main.toJSONString() + param.toJSONString();
        if (tmp.contains("}{")) {
            tmp = tmp.replace("}{", ",");
        }
        return JSONObject.parseObject(tmp);
    }

    public static String encodeImageToBase64(File imageFile) throws IOException {
        try (InputStream inputStream = new FileInputStream(imageFile)) {
            byte[] imageBytes = new byte[(int)imageFile.length()];
            inputStream.read(imageBytes);
            return Base64.getEncoder().encodeToString(imageBytes);
        }
    }

    public static void savefile(String picUrl, String picPath, String picName) throws Exception {

        File file = new File(picPath + picName);
        if (file.exists()) {
            return;
        }
        URL url = new URI(picUrl).toURL();

        // Open a connection to the URL
        URLConnection conn = url.openConnection();

        // Get the input stream from the connection
        InputStream in = conn.getInputStream();

        // Create a file output stream to save the image
        FileOutputStream out = new FileOutputStream(picPath + picName);

        // Loop through the input stream and write to the output stream
        int b;
        while ((b = in.read()) != -1) {
            out.write(b);
        }

        // Close the streams
        out.close();
        in.close();
    }

    public static String getFileCharset(File file) {
        String charset = "GBK";
        byte[] first3Bytes = new byte[3];
        try {
            boolean checked = false;
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
            bis.mark(100);
            int read = bis.read(first3Bytes, 0, 3);
            if (read == -1) {
                bis.close();
                return charset; // 文件编码为 ANSI
            } else if (first3Bytes[0] == (byte)0xFF && first3Bytes[1] == (byte)0xFE) {
                charset = "UTF-16LE"; // 文件编码为 Unicode
                checked = true;
            } else if (first3Bytes[0] == (byte)0xFE && first3Bytes[1] == (byte)0xFF) {
                charset = "UTF-16BE"; // 文件编码为 Unicode big endian
                checked = true;
            } else if (first3Bytes[0] == (byte)0xEF && first3Bytes[1] == (byte)0xBB && first3Bytes[2] == (byte)0xBF) {
                charset = "UTF-8"; // 文件编码为 UTF-8
                checked = true;
            }
            bis.reset();
            if (!checked) {
                while ((read = bis.read()) != -1) {
                    if (read >= 0xF0) {
                        break;
                    }
                    if (0x80 <= read && read <= 0xBF) {// 单独出现BF以下的，也算是GBK
                        break;
                    }
                    if (0xC0 <= read && read <= 0xDF) {
                        read = bis.read();
                        if (0x80 <= read && read <= 0xBF) {// 双字节 (0xC0 - 0xDF)
                            // (0x80 - 0xBF),也可能在GB编码内
                            continue;
                        } else {
                            break;
                        }
                    } else if (0xE0 <= read && read <= 0xEF) { // 也有可能出错，但是几率较小
                        read = bis.read();
                        if (0x80 <= read && read <= 0xBF) {
                            read = bis.read();
                            if (0x80 <= read && read <= 0xBF) {
                                charset = "UTF-8";
                                break;
                            } else {
                                break;
                            }
                        } else {
                            break;
                        }
                    }
                }
            }
            bis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return charset;
    }

    public static String txtFileEncodingConversion(File sourceFile, String sourceEncoding, String targetEncoding)
        throws IOException {
        String targetPath = "/tmp/target/"; // 目标文件路径
        String targetFileName = targetPath + sourceFile.getName();
        File file = new File(targetFileName);
        if (!file.getParentFile().exists()) {
            // 创建上级目录
            file.getParentFile().mkdirs();
        }

        try {
            // 读取文件
            FileInputStream fis = new FileInputStream(sourceFile);
            InputStreamReader isr = new InputStreamReader(fis, sourceEncoding); // 指定原始编码
            BufferedReader br = new BufferedReader(isr);

            // 写入文件
            FileOutputStream fos = new FileOutputStream(targetFileName);
            OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8"); // 指定目标编码
            BufferedWriter bw = new BufferedWriter(osw);

            String line;
            while ((line = br.readLine()) != null) {
                bw.write(line);
                bw.newLine();
            }

            // 关闭流
            br.close();
            bw.close();
        } catch (IOException e) {
            log.error("文件转码失败", e);
        }

        // FileOutputStream fos = new FileOutputStream(new File(targetFileName));
        // OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8"); // 设置目标文件编码为UTF-8
        // BufferedWriter bw = new BufferedWriter(osw);
        //
        // try (BufferedReader br = new BufferedReader(new FileReader(sourceFile.getPath(),
        // Charset.forName(targetEncoding)))) {
        // String line;
        // while ((line = br.readLine()) != null) {
        // bw.write(line);
        // }
        // } catch (IOException e) {
        // log.error("文件转码失败", e);
        // } finally {
        // bw.close();
        // osw.close();
        // }

        return targetFileName;
    }

    public static byte[] toByteArray(InputStream input) throws IOException {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        byte[] buf = new byte[1024];
        for (int n = input.read(buf); n != -1; n = input.read(buf)) {
            os.write(buf, 0, n);
        }
        return os.toByteArray();
    }

    public static int countHtmlPages(String input) {
        // 正则表达式匹配 <html> 标签，忽略大小写，并考虑可能的属性
        String regex = "(?i)<html[^>]*>.*?</html>";
        Pattern pattern = Pattern.compile(regex, Pattern.DOTALL);
        Matcher matcher = pattern.matcher(input);

        int count = 0;
        while (matcher.find()) {
            count++;
        }

        return count;
    }

    // public static String getBody(ServletRequest request) throws IOException {
    // StringBuilder stringBuilder = new StringBuilder();
    // BufferedReader bufferedReader = null;
    // try {
    // // 从请求对象中获取输入流
    // bufferedReader = request.getReader();
    // char[] charBuffer = new char[128];
    // int bytesRead;
    // // 读取输入流中的数据并存储到 StringBuilder 中
    // while ((bytesRead = bufferedReader.read(charBuffer)) != -1) {
    // stringBuilder.append(charBuffer, 0, bytesRead);
    // }
    // } finally {
    // if (bufferedReader != null) {
    // bufferedReader.close();
    // }
    // }
    // // 返回 body 数据
    // return stringBuilder.toString();
    // }

    public static void main(String[] args) {
        // String filePath = "D:\\仙葫.txt";
        // File file = new File(filePath);
        // try {
        // String charSet = detectCharset(filePath);
        // log.info("charSet = {}", charSet);
        // txtFileEncodingConversion(file, charSet, "UTF-8");
        // } catch (IOException e) {
        // e.printStackTrace();
        // }

        try {
            String inputFilePath = "D:\\仙葫.txt"; // 输入文件路径
            String outputFilePath = "D:\\仙葫_utf8.txt"; // 输出文件路径

            // 读取文件
            FileInputStream fis = new FileInputStream(inputFilePath);
            InputStreamReader isr = new InputStreamReader(fis, "gbk"); // 指定原始编码
            BufferedReader br = new BufferedReader(isr);

            // 写入文件
            FileOutputStream fos = new FileOutputStream(outputFilePath);
            OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8"); // 指定目标编码
            BufferedWriter bw = new BufferedWriter(osw);

            String line;
            while ((line = br.readLine()) != null) {
                bw.write(line);
                bw.newLine();
            }

            // 关闭流
            br.close();
            bw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
